///********************************************************************
///* Copyright © 2012 fishr (fishr.flash@gmail.com)  
///********************************************************************


package su.fishr.air.utils.bd 
{
	import flash.data.SQLConnection;
	import flash.data.SQLStatement;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.SQLErrorEvent;
	import flash.events.SQLEvent;
	import flash.filesystem.File;
	import su.fishr.air.utils.bd.dbEvent;
	import su.fishr.air.utils.bd.vo.SQLTable;
	
	  

	/**
	 *  Создает таблицы данных в базе ссылку на которую
	 * получает в конструкторе.
	 * 
	 * @playerversion          AIR 2.0
	 * @langversion            3.0
	 * @author                 fishr
	 * @created                29.02.2012 13:00
	 * @since                  29.02.2012 13:00
	 */
	public  class CreatorSQLTables extends EventDispatcher
	{
		
		
		[Event (name = "base opened", type = "su.fishr.air.utils.bd.dbEvent")]
		[Event (name = "add tables complete", type = "su.fishr.air.utils.bd.dbEvent")]
		
	/**-------------------------------------------------------------------------------
	* 
	*	   						V A R I A B L E ' S 	
	* 
	* --------------------------------------------------------------------------------
	*/
	//{
		static private const AUTHOR:String = "fishr (fishr.flash@gmail.com)";
		/**
		 *  Содержит ссылку на экземпляр SQLStatement для исполнения
		 * SQL-запросов к базе данных с которой работает данный экземпляр CreaterSQLTables
		 * 
		 */
		public const STATEMENT:SQLStatement = new SQLStatement();
		private var _dbPath:File;
		private var _dbTables:Array = new Array();
		private var _dbConnect:SQLConnection;
		
		
		
	//}
	
	/**-------------------------------------------------------------------------------
	* 
	*	 						P R O P E R T I E S 	
	* 
	* --------------------------------------------------------------------------------
	*/
	//{

	//}
	/**-------------------------------------------------------------------------------
	* 
	*								P U B L I C 	
	* 
	* --------------------------------------------------------------------------------
	*/
	//{
	
		/**
		 *  Конструктор класса. Получает в аргументах вызова
		 * ссылку на файл-бд, в виде экз-ра класса File, также
		 * необязательным параметром может быть передан набор (массив),
		 * классов SQLTable, описывающих свойства конкретной
		 * таблицы.
		 * 
		 * @param	path экз-р класса File содержащий ссылку (указатель) на файл-БД
		 * @param	tables массив экземпляров классов SQLTable описывающих конкретные свойства новых таблиц.
		 * @param	target
		 */
		public function CreatorSQLTables(path:File, tables:Array = null, target:IEventDispatcher = null)
		{
			super( target );
			
			_dbPath = path;
			if( tables ) _dbTables = tables;
			_dbConnect = new SQLConnection();
			
			_dbConnect.addEventListener( SQLErrorEvent.ERROR, errorOpenBase );
			_dbConnect.addEventListener( SQLEvent.OPEN, openBase );
			
			_dbConnect.open( _dbPath );
			
		}
		
		/**
		 *  Добавляет новую таблицу в БД.
		 * 
		 * @param value - экземпляр класса SQLTable содержащий характеристики 
		 *                новой таблицы.
		 */
		public function setDbTable(value:SQLTable):void 
		{
	
			_dbTables.push( value );

			if ( this.hasEventListener( dbEvent.BASE_OPENED ) ) this.addEventListener( dbEvent.BASE_OPENED, delaedCrate ) ;
			else createTable( _dbTables.splice( 0, 1 )[0] as SQLTable );
			
		}
		
		/**
		 *  Добавляет таблицы в БД из сообщенного в аргументе массива 
		 *  экземпляров SQLTable
		 * 
		 * @param  value массив экземпляров SQLTable.
		 */
		public function setDbTables( value:Array ):void
		{
			_dbTables = value.slice( 0 );
			
			if ( this.hasEventListener( dbEvent.BASE_OPENED ) ) this.addEventListener( dbEvent.BASE_OPENED, delaedCrate ) ;
			else createTable( _dbTables.splice( 0, 1 )[0] as SQLTable );
		}
		
	//}
	
	/**-------------------------------------------------------------------------------
	* 
	*								P O T E C T E D 	
	* 
	* --------------------------------------------------------------------------------
	*/	
	//{
		/**
		 * Переопределяемый в наследнике метод обработки ошибок
		 * открытия БД.
		 * 
		 * @param	e
		 */
		protected function errorOpenBase(e:SQLErrorEvent):void 
		{
			_dbConnect.removeEventListener( SQLErrorEvent.ERROR, errorOpenBase );
			
			throw new Error( "Ошибка открытия базы данных " + _dbPath + ". Строка запроса: " + STATEMENT.text +  " . Текс ошибки: " + e )
		}
		
		/**
		 *  Переопределяемый  в наследнике метод обработки
		 * ошибок команд к БД.
		 * 
		 * @param	e
		 */
		protected function errorStatement(e:SQLErrorEvent):void 
		{
			throw new Error ( "Ошибка обращения к базе данных " + _dbPath + ". Строка запроса: " + STATEMENT.text + ". Tекст ошибки: " + e );
		}
		
		/**
		 *  Переопределяемый метод - обработчик результатов запросов к БД,
		 * Выполняет обращение к методу-добавителю таблиц сообщая экземпляр класса-описателя
		 * новой таблицы.
		 * В случае если массив полученных классов-таблиц закончился прекращает работу
		 * класса, диспатчит событие окончания процедуры добавления новых таблиц.
		 * @param	e
		 */
		protected function resultSQL(e:SQLEvent):void 
		{
			if ( _dbTables.length )createTable( _dbTables.splice( 0, 1 )[0] as SQLTable );
			else
			{
				STATEMENT.removeEventListener(SQLEvent.RESULT, resultSQL );
				this.dispatchEvent( new dbEvent( dbEvent.ADD_TABLES_COMPLETE ) );
			}
		}

	//}
	
	/**-------------------------------------------------------------------------------
	* 
	*								P R I V A T E 	
	* 
	* --------------------------------------------------------------------------------
	*/	
	//{
		
		/**
		 * @private
		 * 
		 * Обрабатывает событие открытия доступа к базе данных.
		 * Передает дескриптор в экз-р класса SQLStatement - обработчик команд к БД.
		 * Сообщает о том, что доступ к БД получен.
		 * Если в конструктор был сообщен массив классов-таблиц инициализирует
		 * доабавление первой таблицы.
		 * 
		 * @param	e
		 */
		private function openBase(e:SQLEvent):void 
		{
			_dbConnect.removeEventListener( SQLEvent.OPEN, openBase );
			_dbConnect.removeEventListener( SQLErrorEvent.ERROR, errorOpenBase );
			
			STATEMENT.sqlConnection = _dbConnect;
			STATEMENT.addEventListener(SQLErrorEvent.ERROR, errorStatement);
			
			this.dispatchEvent( new dbEvent( dbEvent.BASE_OPENED ) );
			
			if ( _dbTables.length ) createTable( _dbTables.splice( 0, 1 )[0] as SQLTable);
			
		}
		
		/**
		 * @private
		 * Реализует команду добавления очередной таблицы
		 * 
		 * @param	table ссылка на экз-р SQLTables
		 */

		private function createTable( table:SQLTable):void
		{
			STATEMENT.text =  createRequest( table );
			STATEMENT.addEventListener(SQLEvent.RESULT, resultSQL );
			STATEMENT.execute();
		}
		
		/**
		 * @private
		 * Формирует комманду добавленя таблицы
		 * 
		 * @param	table ссылка на экз-р SQLTables
		 * @return строку-комманду для БД.
		 */

		private function createRequest( table:SQLTable ):String
		{
			var requestDB:String = " CREATE TABLE IF NOT EXISTS ";
			requestDB += table.nameTable;
			requestDB += "( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ";
			
			var fields:Array = table.FIELDS;

			fields.reverse();

			var i:uint = fields.length;
			
			while ( i-- )
			{
				requestDB += ", " + fields[i][0] + " " + fields[i][1] + " " + fields[i][2] + " ";
			}
			
			requestDB += ") ";
			
			return requestDB;

		}
		
		/**
		 * @private
		 *  В случае если таблица-цы сообщаются не в конструктор
		 * инициализирует процесс добавления таблиц.
		 * 
		 * @param	e
		 */
		private function delaedCrate( e:dbEvent ):void
		{
			this.removeEventListener( dbEvent.BASE_OPENED, delaedCrate );
			
			createTable( _dbTables.splice( 0, 1 )[0] as SQLTable );
		}
		
	//}
		
		
	}

}